package simplifiedPastry.simpleTester;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.StringTokenizer;
import simplifiedPastry.Message;
import simplifiedPastry.Node;
import simplifiedPastry.NodeId;
import simplifiedPastry.ProtocolVariables;
import simplifiedPastry.exceptions.NodeConnectionException;
import simplifiedPastry.exceptions.NodeStateException;

public class Main {
	/**
	 * @param args
	 * @throws NodeConnectionException 
	 * @throws NodeStateException 
	 * @throws NumberFormatException 
	 * @throws IOException 
	 */
	public static void main(String[] args) {
		if (args.length > 1) {
			try {
				NodeId nodeId = NodeId.random();
				MessagePrinter msgPrinter = new MessagePrinter();
				Node node;
				node = new Node(nodeId, InetAddress.getLocalHost(), Integer.parseInt(args[0]),
										ProtocolVariables.defaultConnectTimeout,
										ProtocolVariables.defaultSendWaitTimeout,
										msgPrinter);
				node.connect(InetAddress.getLocalHost(), Integer.parseInt(args[1]));
				synchronized (nodeId) {
					try {
						nodeId.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				node.disconnect();
				return ;
			} catch (NumberFormatException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (UnknownHostException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NodeStateException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SocketException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (NodeConnectionException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		NodeId nodeId = null;
		MessagePrinter msgPrinter = new MessagePrinter();
		Node node = null;
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in) );
		
		StringTokenizer cmdLine = null;
		String command = null;
		
		while(true) {
			System.out.print(">");
			try {
				cmdLine = new StringTokenizer(br.readLine());
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			int tokenNum = cmdLine.countTokens();
			if(tokenNum == 0)
				continue;
			
			command = cmdLine.nextToken().toLowerCase();
			if(command.equals("nodeid")) {
				try {
					nodeId = new NodeId(NodeId.encodeId(cmdLine.nextToken()));
					node = new Node(nodeId, InetAddress.getLocalHost(), Integer.parseInt(args[0]),
											ProtocolVariables.defaultConnectTimeout,
											ProtocolVariables.defaultSendWaitTimeout,
											msgPrinter);
					System.out.println("nodeId " + nodeId);
				} catch (NumberFormatException e) {
					e.printStackTrace();
					return;
				} catch (UnknownHostException e) {
					e.printStackTrace();
					return;
				}
			} else if(command.equals("newnet"))
			{
				try {
					node.createNewNet();
				} catch (SocketException e) {
					e.printStackTrace();
					return;
				} catch (NodeStateException e) {
					e.printStackTrace();
					return;
				}
				System.out.println("New net created");
			}
			else if(command.equals("disconnect"))
			{
				node.disconnect();
				System.out.println("Node " + nodeId.toString() + " disconnected.");
				return;
			}
			else if(command.equals("send")) {
				if(tokenNum != 3)	{
					System.out.println("Usage: send <nodeId> <message>");
					continue;
				}
				String nodeIdS = cmdLine.nextToken();
				String messageS = cmdLine.nextToken();
				
				node.sendMessage(new Message(messageS.getBytes()),
						new NodeId(NodeId.encodeId(nodeIdS)));
				
			} else if(command.equals("ksearch")) {
				if(tokenNum != 3)	{
					System.out.println("Usage: ksearch <nodeId> <num>");
					continue;
				}
				String nodeIdS = cmdLine.nextToken();
				node.kSearch(new NodeId(NodeId.encodeId(nodeIdS)),
						Integer.parseInt(cmdLine.nextToken()));
			}
			else if(command.equals("join"))	{
				if(tokenNum != 3)	{
					System.out.println("Usage: join <inet_addr> <port>");
					continue;
				}
				
				String inetAddrS = cmdLine.nextToken();
				String portS = cmdLine.nextToken();
				
				System.out.println("Joining <" + inetAddrS + ":" + portS + ">");
				try {
					node.connect(InetAddress.getByName(inetAddrS), Integer.parseInt(portS));
				} catch (NumberFormatException e) {
					e.printStackTrace();
				} catch (NodeStateException e) {
					e.printStackTrace();
					return;
				} catch (SocketException e) {
					e.printStackTrace();
					return;
				} catch (UnknownHostException e) {
					e.printStackTrace();
				} catch (NodeConnectionException e) {
					e.printStackTrace();
				}
				System.out.println("Node " + nodeId.toString() + " joined.");
			}
			else
			{
				System.out.println("Unrecognized command: '" + command + "'\n");
			}
		}
	}
}
